#include "../esyio.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#include "stack.h"
// 求(n!+3)(n->1~10)
int Q8() {
    int sum = 0;
    int fac = 1;
    for (int n = 1;n<=10;++n) {
        fac *= n;
        sum += fac + 3;
    }
    return sum;
}
//给一个不多于6位的正整数，要求：①求出它是几位数；②分别输出每一位数字；③按逆序输出各位数字，例如原数为158，应输出851。
void Q11(int num) {
    int n = 0;
    int nums[6] = {0};
    while (num != 0) {
        nums[n++] = num % 10;
        num /= 10;
    }
    printf("一共%d位",n);
    for (int i = 0;i < n;++i) {
        printf("%d",nums[i]);
    }
}

// 输入一个数a，求a+aa+aaa+aaaa+aaaaa(共a个)
void Q12(int a) {
    int sum = 0,pre = 0, cur = 0;
    for (int i = 0;i<a;++i) {
        cur = pre * 10 + a;
        sum += cur;
        pre = cur;
    }
    PrintInt(sum);

}

//将一个二维数组a的行和列的元素互换（即行列互换），存到另一个二维数组b中
#define M 3
#define N 4
void Q14(int a[M][N],int b[N][M]) {
    for (int i = 0;i<M;i++) {
        for (int j = 0;j<N;++j) {
            b[j][i] = a[i][j];
        }
    }
}
void Test_Q14() {
    int a[M][N] = {
        {1, 2, 3, 0},
        {4, 5, 6, 0},
        {7, 8, 9, 0},
    };
    int b[N][M];
    Q14(a,b);
    for (int i = 0;i<N;i++) {
        for (int j = 0;j<M;++j) {
            PrintInt(b[i][j]);
            putchar(' ');
        }
        Endl();
    }
}

// 输入一行字符，统计其中有多少个单词，单词之间用空格分隔开。
void Q16(char *str) {
    int count = 0;
    int in_word = 0;
    while (*str) {
        if (isalpha(*str)) {
            if (!in_word) {
                count++;
                in_word = 1;
            }
        }
        else {
            in_word = 0;
        }
        str++;
    }
    PrintInt(count);
}


// 用递归法将一个整数n转换成字符串。例如，输入483，应输出字符串“483”，n 的位数不确定，可以是任意位数的整数。
void Q24(int n) {
    if (n == 0) return;
    Q24(n/10);
    putchar('0' + n % 10);
}
int Test_Q24() {
    int n;
    scanf("%d", &n);
    if (n < 0) {
        putchar('-');
        n = -n;
    }
    Q24(n);
    return 0;
}



typedef struct Date {
    int year;
    int month;
    int day;
}Date;


int isRunNian(int year) {
    return (year%4==0 && year%100!=0) || (year%400==0);
}

void Q31(Date date) {
    int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
    if (isRunNian(date.year)) {
        days[1] = 29;
    }
    int sum = 0;
    for (int i = 0; i < date.month-1;i++) {
        sum += days[i];
    }
    sum += date.day;
    PrintInt(sum);
}


#define MAX_ROWS 100
#define MAX_COLS 100

// 找出一个二维数组中的鞍点(暴力解法)
void Q40(int matrix[][MAX_COLS], int rows, int cols) {
    // 遍历矩阵中的每个元素
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            int element = matrix[i][j];
            int is_saddle_point = 1; // 假设当前元素是鞍点
            // 检查当前元素是否是其所在行的最大值
            for (int k = 0; k < cols; ++k) {
                if (matrix[i][k] > element) {
                    is_saddle_point = 0;
                    break;
                }
            }
            // 检查当前元素是否是其所在列的最小值
            for (int k = 0; k < rows; ++k) {
                if (matrix[k][j] < element) {
                    is_saddle_point = 0;
                    break;
                }
            }
            // 如果当前元素是鞍点，则输出其坐标
            if (is_saddle_point) {
                printf("鞍点坐标：(%d, %d)，值：%d\n", i, j, element);
                return; // 找到鞍点后直接返回
            }
        }
    }
    // 如果没有找到鞍点，则输出提示信息
    printf("未找到鞍点\n");
}

// 示例
int Test_Q40() {
    int matrix[MAX_ROWS][MAX_COLS] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
    int rows = 3;
    int cols = 3;
    Q40(matrix, rows, cols);
    return 0;
}


void Q41(char *str) {
    int in_word = 0; // 标记是否处于一个单词中
    int len = 0; // 当前单词的长度
    int start = 0; // 当前单词的起始位置
    int max = 0; // 最长单词的长度
    int max_start = 0; // 最长单词的起始位置

    for (int i = 0; str[i] != '\0'; ++i) {
        if (isalpha(str[i])) {
            len++;
            if (!in_word) { // 如果不在一个单词中，说明是单词的第一个字母
                in_word = 1; // 标记处于单词中
                start = i;
            }
        } else {
            if (in_word) { // 如果之前处于一个单词中，说明是单词的结束位置
                if (len > max) {
                    max = len;
                    max_start = start;
                }
                len = 0;
                in_word = 0; // 标记不处于单词中
            }
        }
    }

    // 输出最长单词
    printf("最长单词：");
    for (int j = max_start; j < max_start + max; ++j) {
        putchar(str[j]);
    }
    printf("\n");
}

// 示例
int Test_Q41() {
    char str[] = "Hello world, this is a test string hahahahahaha!";
    Q41(str);
    return 0;
}

// 输出金字塔图案(9层)
void Q42() {
    for (int i = 0;i<5;i++) { // 五层
        // 打印空格
        for (int j = 0;j < 5-i;++j) {
            putchar(' ');
        }
        for (int j = 0;j < 2*(i+1)-1;++j) {
            putchar('*');
        }
        Endl();
    }
    for (int i = 3;i>=0;--i) { //打印四层
        // 打印空格
        for (int j = 0;j < 5-i;++j) {
            putchar(' ');
        }
        for (int j = 0;j < 2*(i+1)-1;++j) {
            putchar('*');
        }
        Endl();
    }
}

// 有一个已排好序的数组，求输入一个数后，按原来排序的规律将她插入数组中
void Q43(int arr[], int size, int num) {
    if (size == 1) {
        arr[1] = num;
        return;
    }
    // 判断数组是升序还是降序
    int is_asc = arr[0] < arr[1]; // 若第一个元素小于第二个元素，则为升序

    // 查找插入位置
    int i;
    if (is_asc) {
        // 升序数组
        for (i = 0; i < size && arr[i] < num; ++i);
    } else {
        // 降序数组
        for (i = 0; i < size && arr[i] > num; ++i);
    }
    // 将新元素插入数组中
    for (int j = size; j > i; --j) {
        arr[j] = arr[j - 1];
    }
    arr[i] = num;
}


// 第1个字母变成第26个字母，第i个字母变成第（26– i+1）个字母。非字母符号不变。 要求编程序将密码译回原文，并输出密码和原文。
void Q46_Encode(char *str) {
    while (*str) {
        if (*str >= 'A' && *str <= 'Z') {
            *str = 'Z' - (*str - 'A');
        }
        else if (*str >= 'a' && *str <= 'z') {
            *str = 'z' - (*str - 'a');
        }
        str++;
    }
}

void Q46_Decode(char *str) {
    while (*str) {
        if (*str >= 'A' && *str <= 'Z') {
            *str = 'A' + ('Z'- *str);
        }
        else if (*str >= 'a' && *str <= 'z') {
            *str = 'a' + ('z'- *str);
        }
        str++;
    }
}

// 有 n 个人围成一圈，顺序排号。从第一个人开始报数（从1到3报数），凡报到3的人退出圈子，问最后留下来的是原来第几号的那位
void Q47(int n) {
    int *is_live = malloc(sizeof(int)*n);
    for (int i=0;i<n;++i) is_live[i] = 1;
    int k = n;
    int i = 0;
    int count = -1; // 计数,保证第一个人是从0开始
    while (k > 1) {
        if (is_live[i]) {
            // ++后第一个人是1，所以是count == 3
            count = (count+1)%3;
            if (count == 2) {
                is_live[i] = 0;
                k--;
            }
        }
        i = (i+1)%n;
    }
    // 找到最后留下来的人
    for (i = 0; i < n; ++i) {
        if (is_live[i]) {
            printf("最后留下来的是原来第 %d 号的那位\n", i + 1);
            break;
        }
    }
    free(is_live);
}

/*
编写一个函数，使之能完成以下功能：
利用递归方法找出一个数组中的最大值和最小值，要求递归调用函数的格式如下：
MinMaxValue(arr,n,&max,&min)，
*/

void MinMaxValue(int arr[],int n,int *max,int *min){
    if (n < 0){
        return;
    }
    if (arr[n] < *min){
        *min = arr[n];
    }
    if (arr[n] > *max){
        *max = arr[n];
    }
    MinMaxValue(arr,n-1,max,min);
}


void Q56(){
    int arr[] = {0,3,5,6,8,4};
    int max, min;
    MinMaxValue(arr,5,&max,&min);
    printf("max:%d,min:%d",max,min);
}




/*  编写一个函数，使之能完成以下功能：把file1.doc的内容全部复制到file2.doc
    中，file1.doc 中全部是字符(含空格)，要求复制时，在file2.doc中的每一行都要
    加上行号，例如：行号*(其中“*”表示具体的数字)。最后该函数返回file1.doc
    中的字符个数(不包括空格)
*/
void Q57() {
    FILE *fp1 = fopen("D:\\Retest\\Other\\file1.txt","r");
    FILE *fp2 = fopen("D:\\Retest\\Other\\file2.txt","w");
    if (fp1==NULL || fp2==NULL) {
        puts("Error!");
        return;
    }
    int line = 1;
    char ch;
    fprintf(fp2, "%d:", line); // 写入行号
    while ((ch = fgetc(fp1))!= EOF) {

        fputc(ch,fp2);
        if (ch == '\n') {
            line++;
            fprintf(fp2, "%d:", line); // 写入行号
        }
    }
    fclose(fp1);
    fclose(fp2);
}


/*
    一段名为file.c的程序，该程序中含有括号，现要检查程序中的括号是否配对，
    提示：利用堆栈实现。
*/

void Q59(){
    FILE *fp = fopen("D:\\Retest\\Other\\file.c","r");
    if (fp == NULL){
        perror("打开文件失败啦");
    }
    Stack S;
    InitStack(&S);
    char ch;
    while ((ch = fgetc(fp)) != EOF) {
        if (ch == '{' || ch == '[' || ch == '(') {
            Push(&S,ch);
        }
        else if(ch == '}' || ch == ']' || ch == ')') {
            if (isEmpty(S)) {
                printf("Error");
                return;
            }
            char sy = Pop(&S);
            if ((sy == '(' && ch == ')') || (sy == '[' && ch == ']') || (sy == '{' && ch == '}')) {
                continue;
            }
            printf("Error");
            return;
        }
    }

    if (!isEmpty(S)) {
        printf("Error");
    }
    else {
        printf("Currect!");
    }
}

void Q62() {
    char str[] = "Hello**world456&12&&^^^";
    int len = strlen(str);
    int i = 0;
    while (str[i]) {
        if (isalpha(str[i]) || isdigit(str[i])) {
            for (int k = i;k<len;k++) {
                str[k] = str[k+1];
            }
        }
        else {
            i++;
        }
    }
    puts(str);
}

void partition(int arr[],int n) {
    int low = 0, high = n-1;
    int pivot = arr[0];
    while (low < high) {
        while (low < high && arr[high] >= pivot) high--;
        arr[low] = arr[high];
        while (low < high && arr[low] <= pivot) low++;
        arr[high] = arr[low];
    }
    arr[low] = pivot;
}

//编写一个函数，把整数序列分成两个部分，使得左边部分都不大于右边部分，不需要排序。
void Q66() {
    int arr[] = {5,4,3,6,2,9,8,7,1};
    partition(arr,9);
    PrintNums(arr,9);

}


// 有两字符数组s和t，求t在s中出现第一次的开始位置
int strStr(char *s, char *t) {
    if (!*t) return 0; // 如果t为空字符串，返回0

    int s_len = strlen(s);
    int t_len = strlen(t);

    if (!*s || s_len < t_len) return -1; // 如果s为空字符串，或者s的长度小于t的长度，返回-1

    for (int i = 0; i <= s_len - t_len; ++i) {
        int j;
        for (j = 0; j < t_len; ++j) {
            if (s[i + j] != t[j]) break; // 如果s[i+j]和t[j]不相等，退出内层循环
        }
        if (j == t_len) return i; // 如果内层循环完整执行完毕，说明找到了匹配，返回i
    }

    return -1; // 未找到匹配，返回-1
}

void Q72() {
    char str1[] = {"ABCABC"};
    char str2[] = {"CA"};
    PrintInt(strStr(str1,str2));

}


int extractToInt(char *str,int nums[],int n) {
    int k = 0;
    int i = 0;
    while (str[i] != '#' && str[i] != 0) {
        if (!isdigit(str[i])) {
            i++;
            continue;
        }
        int sum = 0;
        while (isdigit(str[i])) {
            sum *= 10;
            sum += str[i] - '0';
            i++;
        }
        if (k>=n) {
            return -1;
        }
        else {
            nums[k++] = sum;
        }
    }
    return k;
}

void Q73() {
    char str[] = "A44BC125D56*dd4";
    int nums[10];
    int n = extractToInt(str,nums,10);
    PrintNums(nums,n);
}







int main() {
    Q73();
    return 0;
}
